// transformation matrices 
//--------------------------------------------------------------------------------------
matrix World;						// The World matrix 4x4
matrix View;						// The View Matrix 4x4
matrix Projection;					// The Projection Matrix 4x4
matrix MVP;                         // The ModelViewProjection Matrix 4x4

// Texture 
//--------------------------------------------------------------------------------------
Texture2D shaderTexture;			// The active texture map 
int shaderTextureValid;

// Texture map sampler
//--------------------------------------------------------------------------------------
SamplerState SampleType
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

//LIGHTING STRUCTURES AND VARIABLES
//--------------------------------------------------------------------------------------
struct PointLight
{
    float4 color;
    float3 position;
};

struct _Material
{
    float4 ambient, diffuse, specular;
    float shininess;
};

//lighting vars
PointLight cameraLight;
_Material Material;
float4 AmbientLight;
float3 Eye;
float  QuadricAttenuation = 0.0002;


//VERTEX AND PIXEL SHADER INPUTS
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
    float4 Pos : POSITION;
    float2 Tex : TEXCOORD; 
    float3 Normal : NORMAL;  
};

//pixel shader inputs
struct PS_INPUT_PV
{
    float4 Pos		: SV_POSITION;   
    float2 Tex		: TEXCOORD;
    float4 Color	: COLOR;
};

struct PS_INPUT_PP_PHONG
{
    float4 Pos		: SV_POSITION;   
    float4 WorldPos : POSITION;
    float2 Tex		: TEXCOORD;	
    float3 Normal	: TEXCOORD1;		
};

float4 calcPhongLightingDirectionLight( _Material M, float4 LColor, float3 N, float3 worldPos, float3 lightPos, float3 V, float3 R )
{
    float3 vL = lightPos-worldPos;      // The light vector from point light to the surface point
    float rayLen = length(vL);          // The length from point light to the surface point

    float3 L = normalize(vL);           // Light direction
    
    
    float4 Iar = M.ambient.r * AmbientLight;
    float4 Iag = M.ambient.g * AmbientLight;
    float4 Iab = M.ambient.b * AmbientLight;

    float4 Idr = M.diffuse * saturate( dot(N,L) );
    float4 Idg = M.diffuse * saturate( dot(N,L) );
    float4 Idb = M.diffuse * saturate( dot(N,L) );

    float4 Isr = M.specular * pow( saturate(dot(R,V)), M.shininess );
    float4 Isg = M.specular * pow( saturate(dot(R,V)), M.shininess );
    float4 Isb = M.specular * pow( saturate(dot(R,V)), M.shininess );

    float4 Ia = float4(Iar.r,Iag.g,Iab.b,1.0);
    float4 Id = float4(Idr.r,Idg.g,Idb.b,1.0);
    float4 Is = float4(Isr.r,Isg.g,Isb.b,1.0);

    float lambertTerm = dot(N,L);
    if( lambertTerm > 0.0 )
    {
        Id = float4(0.5,0.5,0.5,1.0);
    }
    else
    {
        LColor = float4(0,0,0,0);
    }
    

    
    Ia.a = Id.a = Is.a = LColor.a = 0.3;
    return Ia + (Id + Is) * LColor;
}

//--------------------------------------------------------------------------------------
// Phong Lighting Reflection Model
//--------------------------------------------------------------------------------------
float4 calcPhongLighting( _Material M, float4 LColor, float3 N, float3 worldPos, float3 lightPos, float3 V, float3 R )
{	
    
    float r = 10.0;

    float3 L = lightPos - worldPos;
    float distance = length(L);

    float d = max(distance - r, 0);

    L /= distance;
    
    // calculate basic attenuation
    float denom = d/r + 1;
    float attenuation = 1 / (denom*denom);
    
    // scale and bias attenuation such that:
    //   attenuation == 0 at extent of max influence
    //   attenuation == 1 when d == 0
    float cutoff = 0.00001;
    attenuation = (attenuation - cutoff) / (1 - cutoff);

    attenuation = max(attenuation, 0);
    float fdot = max(dot(L, N), 0);

    float4 Ia = M.ambient * AmbientLight;
    float4 Id = M.diffuse * saturate( dot(N,L) );

    
    Ia.a = Id.a = LColor.a = 0.3;

    return Ia + LColor * fdot * attenuation;

} 

//--------------------------------------------------------------------------------------
// PER PIXEL LIGHTING 
//--------------------------------------------------------------------------------------
PS_INPUT_PP_PHONG VS_PIXEL_LIGHTING_PHONG( VS_INPUT input )
{
    PS_INPUT_PP_PHONG output;
    
    //transform position to clip space - keep worldspace position
    output.WorldPos = mul( input.Pos, World );
    output.Pos = mul( output.WorldPos, View );    
    output.Pos = mul( output.Pos, Projection );	
    
    //set texture coords
    output.Tex = input.Tex;
    
    //set required lighting vectors for interpolation
    output.Normal = normalize( mul(input.Normal, (float3x3)World) );
   
    return output;  
}

float4 PS_PIXEL_LIGHTING_PHONG( PS_INPUT_PP_PHONG input ) : SV_Target
{     
    //calculate lighting vectors - renormalize vectors
    input.Normal = normalize( input.Normal );

    float3 V = normalize( Eye - (float3) input.WorldPos );

    //DONOT USE -light.pos since the reflection returns a ray from the surface
    float3 R = reflect( cameraLight.position, input.Normal);
    
    //calculate lighting		
    float4 I = calcPhongLighting( Material, cameraLight.color, input.Normal, input.WorldPos, cameraLight.position, V, R );
    
    //with texturing
    float4 color = I;
    if( shaderTextureValid )
    {
        float4 textureColor = shaderTexture.Sample(SampleType, input.Tex);
        color = I*textureColor;
        color.a = textureColor.a;
    }
    else
    {
        color = Material.ambient+I*(Material.diffuse);
        color.a = Material.diffuse.a;
    }
    return color;
    //return float4(input.Normal,1);
    //return float4((input.Normal)/2+float3(0.5,0.5,0.5),1);
    
    //no texturing pure lighting
    //return I;    
}

technique10 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS_PIXEL_LIGHTING_PHONG() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PS_PIXEL_LIGHTING_PHONG() ) );
    }
}
